This notebook will contain the code needed to execute our data analysis project and answer the questions we would like to ask of the Spotify and YouTube data from Kaggle.

Load the libraries

library(tidyverse)
library(lubridate)
library(janitor)
library(tidytext)
library(rvest)

Load and clean data

spotify_youtube <- read_csv("data/Spotify_Youtube.csv") %>%
clean_names() %>%
rename(number = x1) %>%
  select(-c(number)) %>%
mutate(duration_secs = duration_ms/1000, duration_mins = duration_ms/60000)

glimpse(spotify_youtube)

Basic exploratory analysis

** The dataset has 20,718 rows and 28 columns. There are some NA values within the YouTube data which could serve as a limitation. Similarly, within the YouTube description values, some of the descriptions have emojis or other characters and symbols that could be difficult to work with. Another limitation could arise with the values in the instrumentalness column since they include negative exponents which could also be difficult to work with for different analysis calculations. The original source of the data defines the columns well, otherwise we may make them more complicated. Since the data includes artists whose music is on Spotify but probably not every artist in the world, we would not be able to make assumptions about the music industry as a whole. Another limitation we can notice is that some of the songs that fall under an artist’s most popular songs are feautres of said artist on another song. This can be kind of confusing, but we might be able to work around it using filters once we start more analysis. However, this data is also helpful for answering our question about how collaborations affect an artist’s popularity. One code we would need to make note of is ‘key,’ which denotes pitch notation but we need to find a way to make it easily apparent what the pitch is rather than just seeing a number. There could also be issues with repeat songs when songs are on more than one album, although sometimes it will be the same song but a slightly different rendition.

##Questions

Question 1: Which attributes, such as danceability, energy, loudness, etc., tend to have a correlation with the most streamed songs?

Analysis: After using code to select the variables we wanted to work with, we found the correlation coefficient for each song attribute in relation to the number of streams for each song. After finding the correlation coefficients, we calculated the mean among the coefficients for each attribute to average it out. After that, we looked for the maximum value among all the means, and found that danceability and streams had the highest positive correlation coefficient of about 0.073. There were some previous errors due to some values being NA, but using the filter for complete cases got rid of them, and the data we did use was so large that it provided a general idea of which attribute had the greatest correlation to number of streams.

attribute_correlate_stream <- spotify_youtube %>% 
  select(danceability, energy, key, loudness, speechiness, acousticness, instrumentalness, liveness, valence, tempo, stream) %>% 
  filter(complete.cases(.)) %>%
## find the correlation coefficient between each attribute and number of spotify streams 
   mutate(
    dance_cor = cor(danceability, stream),
    energy_cor = cor(energy, stream),
    key_cor = cor(key, stream),
    speech_cor = cor(speechiness, stream),
    acoustic_cor = cor(acousticness, stream),
    instrumental_cor = cor(instrumentalness, stream),
    live_cor = cor(liveness, stream),
    valence_cor = cor(valence, stream),
    tempo_cor = cor(tempo, stream)
  ) %>% 
## find the mean correlation coefficient for each attribute
  summarise(
    mean_dance_cor = mean(dance_cor),
    mean_energy_cor = mean(energy_cor),
    mean_key_cor = mean(key_cor),
    mean_speech_cor = mean(speech_cor),
    mean_acoustic_cor = mean(acoustic_cor),
    mean_instrumental_cor = mean(instrumental_cor),
    mean_live_cor = mean(live_cor),
    mean_valence_cor = mean(valence_cor),
    mean_tempo_cor = mean(tempo_cor)
  )
##output the highest value among the mean coefficients
max_value <- apply(attribute_correlate_stream, 1, max)
  

Question 2: Does higher engagement on YouTube videos lead to more streams of the song from the video on Spotify? Is there a relationship that exists between social engagement and streams?

Analysis: In order to find and map out the correlation between Youtube video views and Spotify streams, we first grouped the data by artist and then summarised the data by the sum of views and sum of streams for each artist. After that, we plotted the data into a scatter plot with a line of best fit, which shows that there is a slight positive correlation between number of views on Youtube and number of streams on Spotify. This means that it can be generally true that as one value increases, so does the other. While doing this, we divided the totals by 1,000,000 because the numbers would have been to large to easily grasp.

##code to find the total number of views and streams (divided by 1,000,000 because numbers were too large to work with)
streams_views <- spotify_youtube %>% 
  select(artist, track, stream, views) %>% 
  mutate(difference = abs(stream-views)) %>% 
  group_by(artist) %>% 
  summarise(
    total_views = sum(views)/1000000,
    total_streams = sum(stream)/1000000,
  )
##create a scatterplot with line of best fit
streams_views %>% 
  ggplot(aes(x=total_streams, y=total_views))+
  geom_point(size=2)+
  theme_minimal()+
  geom_smooth(method = "lm")+
  labs(
    title = "Correlation between an artist's Spotify Streams and Youtube Views",
    x = "Number of Streams on Spotify",
    y = "Number of Views on Youtube"
  )


##what was happening when that wasn't the case, who was successful on spotify and then not youtube

Question 3: How many videos with a high number of streams are coming from licensed content?

Analysis: Most videos on YouTube with views over 500 million are coming from licensed content. However, we found that there are some outliers. About 54 videos were unlicensed and 15 channels posted unlicensed videos that were also classified as the official video for the track. Some channels say they are official, like Major Lazer Official, and then they only have unlicensed content on the platform. There is no one consistent theme or trend between the channels that have posted unlicensed content, though it seems like some of them are from countries outside of the U.S. or rappers and DJs. Redbox also posted unlicensed videos, which is interesting coming from a company even though it is not as popular anymore. It seems like some channels are definitely repurposing content from an unverified user, like WORLDSTARHIPHOP or perhaps other content is remixes or live performances in the case of DJs. In doing pivot wider, we can filter for licensed and unlicensed content as well as official videos and view the total number of views for each sorted by channel.

youtube_high_views <- spotify_youtube %>%
  filter(views > 500000000)

youtube_high_views %>%
  group_by(artist) %>%
  summarise (
    count_licensed = n()
  ) %>%
  arrange(desc(count_licensed))

youtube_high_views %>%
  filter(licensed == FALSE) 

youtube_high_views %>%
  group_by(channel, licensed) %>%
  summarize(total_views = sum(views)) %>% 
  pivot_wider(names_from = licensed, values_from = total_views)
`summarise()` has grouped output by 'channel'. You can override using the `.groups` argument.
youtube_high_views %>%
  group_by(channel, official_video) %>%
  summarize(total_views = sum(views)) %>% 
  pivot_wider(names_from = official_video, values_from = total_views) %>% 
  filter(`FALSE` > 0)
`summarise()` has grouped output by 'channel'. You can override using the `.groups` argument.
##how to get totals for licensed and unlicensed? play around with view numbers
##group by licensed column and then used pivot wider, take the values and make total columns for each 

Question 4: How do collaborations or features on a song affect its popularity on Spotify and YouTube? What are the most popular collaborations?

Analysis: Some artists definitely seem to be more successful with their songs that have collaborators on the track compared to songs where they are the sole artist. We were trying to do a similar analysis to the question above using pivot_wider to compare the number of streams for songs with a collaborator and without so we could see which artists would be best to collaborate with if you want your song to reach the most people. We ran into an error trying to use pivot wider in the end, so we will definitely need to brainstorm more solutions that will move us past this dead end before we complete more analysis. Either way, Post Malone is the only artist who had streams in the top 10 for both a single song and a collaboration. Mackelmore and Ryan Lewis were also in the top 10 highest number of streams for their collaborative songs, but fall behind for single songs. Also, we noticed a complication with the data when doing an analysis like this to answer the question because songs will appear twice under the different artists’ names even though it is the same song. This can be seen especially with Mackelmore and Ryan Lewis since the song appears under Mackelmore, Ryan Lewis and Mackelmore and Ryan Lewis. Industry Baby and Levitating also appear twice, once under each artist’s name, throwing off the top 10 most streamed collaborative songs.

spotify_youtube %>%
  group_by(artist) %>%
  filter(str_detect(track, 'feat.')) %>%
  arrange(desc(stream))


spotify_youtube %>%
  group_by(artist) %>%
  filter(!str_detect(track,'feat.')) %>%
  arrange(desc(stream))

##I played around with unique words for the descriptions of YouTube videos but then decided to ditch my efforts because they weren’t really that relevant to any major newsworthy findings.

unique_words %>%
  count(word, sort = TRUE) %>%
  top_n(25) %>%
  mutate(word = reorder(word, n))
Selecting by n

Question 5: Do singles or songs from full albums get more streams? What about views on YouTube? Which artists have more success with singles compared to full albums and vice versa?

Analysis: More well known American artists were in the top 10 highest views for YouTube videos coming from songs that were part of a full album. A lot of the singles were also songs that had collaborations between artists. None of the artists who had the top number of streams for singles also had the top number of streams for songs on a full album. Perhaps collaborative songs also perform better when they are a single rather than featured in an album. The highest number of streams for a song that came from an album was The Weeknd’s “Blinding Lights” which had about a billion more streams than Halsey’s “Closer” which is the top single with the most amount of streams. The top videos with the highest views for singles and regular album tracks were also much different than the results from the Spotify streams in these categories. What this could tell us is that maybe jsut because a song is popular does not mean the video to go with it will be as well. There are deeper visual aspects and social trends that may contribute more to the number of views on YouTube.

youtube_high_views %>%
filter(album_type == "single") %>%
  group_by(artist) %>%
  arrange(desc(views))


youtube_high_views %>%
filter(album_type == "album") %>%
  group_by(artist) %>%
  arrange(desc(views))
NA

Our most newsworthy finding So far, we think our most newsworthy piece of analysis comes from either the licensed and unlicensed content on YouTube or the analysis of artist collaborations. We think that once we are able to complete more analysis on artist collaborations, it would make for a really interesting article about who to feature on your track if you want your song to amass a lot of streams on Spotify. From what we have seen, there have not been any articles with a central focus along the lines of “Here’s who to make songs with if you want them to take off,” which we think could be an impactful finding in and around the music community. Also, with the consumption of video on the rise between TikTok and YouTube, we think it is newsworthy to question why certain channels have unlicensed content or how their videos can be official but unlicensed. As we learn more about how to navigate social media spaces in terms of regulating content and copyright, perhaps these findings can provide more insight for those who make social media rules or who work for the social media companies and are trying to limit unlicensed content.

LS0tCnRpdGxlOiAiRGF0YSBBbmFseXNpcyBQcm9qZWN0IgpuYW1lczogIktpZXJzdGVuIEhhY2tlciBhbmQgU2hlcndpbi1OZXN0b3IgRXNndWVycmEiCmRhdGU6ICI0LTExLTIwMjMiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KClRoaXMgbm90ZWJvb2sgd2lsbCBjb250YWluIHRoZSBjb2RlIG5lZWRlZCB0byBleGVjdXRlIG91ciBkYXRhIGFuYWx5c2lzIHByb2plY3QgYW5kIGFuc3dlciB0aGUgcXVlc3Rpb25zIHdlIHdvdWxkIGxpa2UgdG8gYXNrIG9mIHRoZSBTcG90aWZ5IGFuZCBZb3VUdWJlIGRhdGEgZnJvbSBLYWdnbGUuCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQpgYGAKCiMjIyBMb2FkIHRoZSBsaWJyYXJpZXMKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGx1YnJpZGF0ZSkKbGlicmFyeShqYW5pdG9yKQpsaWJyYXJ5KHRpZHl0ZXh0KQpsaWJyYXJ5KHJ2ZXN0KQpgYGAKCiMjIyBMb2FkIGFuZCBjbGVhbiBkYXRhCmBgYHtyfQpzcG90aWZ5X3lvdXR1YmUgPC0gcmVhZF9jc3YoImRhdGEvU3BvdGlmeV9Zb3V0dWJlLmNzdiIpICU+JQpjbGVhbl9uYW1lcygpICU+JQpyZW5hbWUobnVtYmVyID0geDEpICU+JQogIHNlbGVjdCgtYyhudW1iZXIpKSAlPiUKbXV0YXRlKGR1cmF0aW9uX3NlY3MgPSBkdXJhdGlvbl9tcy8xMDAwLCBkdXJhdGlvbl9taW5zID0gZHVyYXRpb25fbXMvNjAwMDApCgpnbGltcHNlKHNwb3RpZnlfeW91dHViZSkKYGBgCgojIyMgQmFzaWMgZXhwbG9yYXRvcnkgYW5hbHlzaXMKKiogVGhlIGRhdGFzZXQgaGFzIDIwLDcxOCByb3dzIGFuZCAyOCBjb2x1bW5zLiBUaGVyZSBhcmUgc29tZSBOQSB2YWx1ZXMgd2l0aGluIHRoZSBZb3VUdWJlIGRhdGEgd2hpY2ggY291bGQgc2VydmUgYXMgYSBsaW1pdGF0aW9uLiBTaW1pbGFybHksIHdpdGhpbiB0aGUgWW91VHViZSBkZXNjcmlwdGlvbiB2YWx1ZXMsIHNvbWUgb2YgdGhlIGRlc2NyaXB0aW9ucyBoYXZlIGVtb2ppcyBvciBvdGhlciBjaGFyYWN0ZXJzIGFuZCBzeW1ib2xzIHRoYXQgY291bGQgYmUgZGlmZmljdWx0IHRvIHdvcmsgd2l0aC4gQW5vdGhlciBsaW1pdGF0aW9uIGNvdWxkIGFyaXNlIHdpdGggdGhlIHZhbHVlcyBpbiB0aGUgaW5zdHJ1bWVudGFsbmVzcyBjb2x1bW4gc2luY2UgdGhleSBpbmNsdWRlIG5lZ2F0aXZlIGV4cG9uZW50cyB3aGljaCBjb3VsZCBhbHNvIGJlIGRpZmZpY3VsdCB0byB3b3JrIHdpdGggZm9yIGRpZmZlcmVudCBhbmFseXNpcyBjYWxjdWxhdGlvbnMuIFRoZSBvcmlnaW5hbCBzb3VyY2Ugb2YgdGhlIGRhdGEgZGVmaW5lcyB0aGUgY29sdW1ucyB3ZWxsLCBvdGhlcndpc2Ugd2UgbWF5IG1ha2UgdGhlbSBtb3JlIGNvbXBsaWNhdGVkLiBTaW5jZSB0aGUgZGF0YSBpbmNsdWRlcyBhcnRpc3RzIHdob3NlIG11c2ljIGlzIG9uIFNwb3RpZnkgYnV0IHByb2JhYmx5IG5vdCBldmVyeSBhcnRpc3QgaW4gdGhlIHdvcmxkLCB3ZSB3b3VsZCBub3QgYmUgYWJsZSB0byBtYWtlIGFzc3VtcHRpb25zIGFib3V0IHRoZSBtdXNpYyBpbmR1c3RyeSBhcyBhIHdob2xlLiBBbm90aGVyIGxpbWl0YXRpb24gd2UgY2FuIG5vdGljZSBpcyB0aGF0IHNvbWUgb2YgdGhlIHNvbmdzIHRoYXQgZmFsbCB1bmRlciBhbiBhcnRpc3QncyBtb3N0IHBvcHVsYXIgc29uZ3MgYXJlIGZlYXV0cmVzIG9mIHNhaWQgYXJ0aXN0IG9uIGFub3RoZXIgc29uZy4gVGhpcyBjYW4gYmUga2luZCBvZiBjb25mdXNpbmcsIGJ1dCB3ZSBtaWdodCBiZSBhYmxlIHRvIHdvcmsgYXJvdW5kIGl0IHVzaW5nIGZpbHRlcnMgb25jZSB3ZSBzdGFydCBtb3JlIGFuYWx5c2lzLiBIb3dldmVyLCB0aGlzIGRhdGEgaXMgYWxzbyBoZWxwZnVsIGZvciBhbnN3ZXJpbmcgb3VyIHF1ZXN0aW9uIGFib3V0IGhvdyBjb2xsYWJvcmF0aW9ucyBhZmZlY3QgYW4gYXJ0aXN0J3MgcG9wdWxhcml0eS4gT25lIGNvZGUgd2Ugd291bGQgbmVlZCB0byBtYWtlIG5vdGUgb2YgaXMgJ2tleSwnIHdoaWNoIGRlbm90ZXMgcGl0Y2ggbm90YXRpb24gYnV0IHdlIG5lZWQgdG8gZmluZCBhIHdheSB0byBtYWtlIGl0IGVhc2lseSBhcHBhcmVudCB3aGF0IHRoZSBwaXRjaCBpcyByYXRoZXIgdGhhbiBqdXN0IHNlZWluZyBhIG51bWJlci4gVGhlcmUgY291bGQgYWxzbyBiZSBpc3N1ZXMgd2l0aCByZXBlYXQgc29uZ3Mgd2hlbiBzb25ncyBhcmUgb24gbW9yZSB0aGFuIG9uZSBhbGJ1bSwgYWx0aG91Z2ggc29tZXRpbWVzIGl0IHdpbGwgYmUgdGhlIHNhbWUgc29uZyBidXQgYSBzbGlnaHRseSBkaWZmZXJlbnQgcmVuZGl0aW9uLgoKIyNRdWVzdGlvbnMKCioqUXVlc3Rpb24gMTogV2hpY2ggYXR0cmlidXRlcywgc3VjaCBhcyBkYW5jZWFiaWxpdHksIGVuZXJneSwgbG91ZG5lc3MsIGV0Yy4sIHRlbmQgdG8gaGF2ZSBhIGNvcnJlbGF0aW9uIHdpdGggdGhlIG1vc3Qgc3RyZWFtZWQgc29uZ3M/KioKCioqQW5hbHlzaXMqKjogQWZ0ZXIgdXNpbmcgY29kZSB0byBzZWxlY3QgdGhlIHZhcmlhYmxlcyB3ZSB3YW50ZWQgdG8gd29yayB3aXRoLCB3ZSBmb3VuZCB0aGUgY29ycmVsYXRpb24gY29lZmZpY2llbnQgZm9yIGVhY2ggc29uZyBhdHRyaWJ1dGUgaW4gcmVsYXRpb24gdG8gdGhlIG51bWJlciBvZiBzdHJlYW1zIGZvciBlYWNoIHNvbmcuIEFmdGVyIGZpbmRpbmcgdGhlIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50cywgd2UgY2FsY3VsYXRlZCB0aGUgbWVhbiBhbW9uZyB0aGUgY29lZmZpY2llbnRzIGZvciBlYWNoIGF0dHJpYnV0ZSB0byBhdmVyYWdlIGl0IG91dC4gQWZ0ZXIgdGhhdCwgd2UgbG9va2VkIGZvciB0aGUgbWF4aW11bSB2YWx1ZSBhbW9uZyBhbGwgdGhlIG1lYW5zLCBhbmQgZm91bmQgdGhhdCBkYW5jZWFiaWxpdHkgYW5kIHN0cmVhbXMgaGFkIHRoZSBoaWdoZXN0IHBvc2l0aXZlIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50IG9mIGFib3V0IDAuMDczLiBUaGVyZSB3ZXJlIHNvbWUgcHJldmlvdXMgZXJyb3JzIGR1ZSB0byBzb21lIHZhbHVlcyBiZWluZyBOQSwgYnV0IHVzaW5nIHRoZSBmaWx0ZXIgZm9yIGNvbXBsZXRlIGNhc2VzIGdvdCByaWQgb2YgdGhlbSwgYW5kIHRoZSBkYXRhIHdlIGRpZCB1c2Ugd2FzIHNvIGxhcmdlIHRoYXQgaXQgcHJvdmlkZWQgYSBnZW5lcmFsIGlkZWEgb2Ygd2hpY2ggYXR0cmlidXRlIGhhZCB0aGUgZ3JlYXRlc3QgY29ycmVsYXRpb24gdG8gbnVtYmVyIG9mIHN0cmVhbXMuCgpgYGB7cn0KYXR0cmlidXRlX2NvcnJlbGF0ZV9zdHJlYW0gPC0gc3BvdGlmeV95b3V0dWJlICU+JSAKICBzZWxlY3QoZGFuY2VhYmlsaXR5LCBlbmVyZ3ksIGtleSwgbG91ZG5lc3MsIHNwZWVjaGluZXNzLCBhY291c3RpY25lc3MsIGluc3RydW1lbnRhbG5lc3MsIGxpdmVuZXNzLCB2YWxlbmNlLCB0ZW1wbywgc3RyZWFtKSAlPiUgCiAgZmlsdGVyKGNvbXBsZXRlLmNhc2VzKC4pKSAlPiUKIyMgZmluZCB0aGUgY29ycmVsYXRpb24gY29lZmZpY2llbnQgYmV0d2VlbiBlYWNoIGF0dHJpYnV0ZSBhbmQgbnVtYmVyIG9mIHNwb3RpZnkgc3RyZWFtcyAKICAgbXV0YXRlKAogICAgZGFuY2VfY29yID0gY29yKGRhbmNlYWJpbGl0eSwgc3RyZWFtKSwKICAgIGVuZXJneV9jb3IgPSBjb3IoZW5lcmd5LCBzdHJlYW0pLAogICAga2V5X2NvciA9IGNvcihrZXksIHN0cmVhbSksCiAgICBzcGVlY2hfY29yID0gY29yKHNwZWVjaGluZXNzLCBzdHJlYW0pLAogICAgYWNvdXN0aWNfY29yID0gY29yKGFjb3VzdGljbmVzcywgc3RyZWFtKSwKICAgIGluc3RydW1lbnRhbF9jb3IgPSBjb3IoaW5zdHJ1bWVudGFsbmVzcywgc3RyZWFtKSwKICAgIGxpdmVfY29yID0gY29yKGxpdmVuZXNzLCBzdHJlYW0pLAogICAgdmFsZW5jZV9jb3IgPSBjb3IodmFsZW5jZSwgc3RyZWFtKSwKICAgIHRlbXBvX2NvciA9IGNvcih0ZW1wbywgc3RyZWFtKQogICkgJT4lIAojIyBmaW5kIHRoZSBtZWFuIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50IGZvciBlYWNoIGF0dHJpYnV0ZQogIHN1bW1hcmlzZSgKICAgIG1lYW5fZGFuY2VfY29yID0gbWVhbihkYW5jZV9jb3IpLAogICAgbWVhbl9lbmVyZ3lfY29yID0gbWVhbihlbmVyZ3lfY29yKSwKICAgIG1lYW5fa2V5X2NvciA9IG1lYW4oa2V5X2NvciksCiAgICBtZWFuX3NwZWVjaF9jb3IgPSBtZWFuKHNwZWVjaF9jb3IpLAogICAgbWVhbl9hY291c3RpY19jb3IgPSBtZWFuKGFjb3VzdGljX2NvciksCiAgICBtZWFuX2luc3RydW1lbnRhbF9jb3IgPSBtZWFuKGluc3RydW1lbnRhbF9jb3IpLAogICAgbWVhbl9saXZlX2NvciA9IG1lYW4obGl2ZV9jb3IpLAogICAgbWVhbl92YWxlbmNlX2NvciA9IG1lYW4odmFsZW5jZV9jb3IpLAogICAgbWVhbl90ZW1wb19jb3IgPSBtZWFuKHRlbXBvX2NvcikKICApCiMjb3V0cHV0IHRoZSBoaWdoZXN0IHZhbHVlIGFtb25nIHRoZSBtZWFuIGNvZWZmaWNpZW50cwptYXhfdmFsdWUgPC0gYXBwbHkoYXR0cmlidXRlX2NvcnJlbGF0ZV9zdHJlYW0sIDEsIG1heCkKICAKYGBgCgoqKlF1ZXN0aW9uIDI6IERvZXMgaGlnaGVyIGVuZ2FnZW1lbnQgb24gWW91VHViZSB2aWRlb3MgbGVhZCB0byBtb3JlIHN0cmVhbXMgb2YgdGhlIHNvbmcgZnJvbSB0aGUgdmlkZW8gb24gU3BvdGlmeT8gSXMgdGhlcmUgYSByZWxhdGlvbnNoaXAgdGhhdCBleGlzdHMgYmV0d2VlbiBzb2NpYWwgZW5nYWdlbWVudCBhbmQgc3RyZWFtcz8qKgoKKipBbmFseXNpcyoqOiBJbiBvcmRlciB0byBmaW5kIGFuZCBtYXAgb3V0IHRoZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIFlvdXR1YmUgdmlkZW8gdmlld3MgYW5kIFNwb3RpZnkgc3RyZWFtcywgd2UgZmlyc3QgZ3JvdXBlZCB0aGUgZGF0YSBieSBhcnRpc3QgYW5kIHRoZW4gc3VtbWFyaXNlZCB0aGUgZGF0YSBieSB0aGUgc3VtIG9mIHZpZXdzIGFuZCBzdW0gb2Ygc3RyZWFtcyBmb3IgZWFjaCBhcnRpc3QuIEFmdGVyIHRoYXQsIHdlIHBsb3R0ZWQgdGhlIGRhdGEgaW50byBhIHNjYXR0ZXIgcGxvdCB3aXRoIGEgbGluZSBvZiBiZXN0IGZpdCwgd2hpY2ggc2hvd3MgdGhhdCB0aGVyZSBpcyBhIHNsaWdodCBwb3NpdGl2ZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIG51bWJlciBvZiB2aWV3cyBvbiBZb3V0dWJlIGFuZCBudW1iZXIgb2Ygc3RyZWFtcyBvbiBTcG90aWZ5LiBUaGlzIG1lYW5zIHRoYXQgaXQgY2FuIGJlIGdlbmVyYWxseSB0cnVlIHRoYXQgYXMgb25lIHZhbHVlIGluY3JlYXNlcywgc28gZG9lcyB0aGUgb3RoZXIuIFdoaWxlIGRvaW5nIHRoaXMsIHdlIGRpdmlkZWQgdGhlIHRvdGFscyBieSAxLDAwMCwwMDAgYmVjYXVzZSB0aGUgbnVtYmVycyB3b3VsZCBoYXZlIGJlZW4gdG8gbGFyZ2UgdG8gZWFzaWx5IGdyYXNwLiAKCmBgYHtyfQojI2NvZGUgdG8gZmluZCB0aGUgdG90YWwgbnVtYmVyIG9mIHZpZXdzIGFuZCBzdHJlYW1zIChkaXZpZGVkIGJ5IDEsMDAwLDAwMCBiZWNhdXNlIG51bWJlcnMgd2VyZSB0b28gbGFyZ2UgdG8gd29yayB3aXRoKQpzdHJlYW1zX3ZpZXdzIDwtIHNwb3RpZnlfeW91dHViZSAlPiUgCiAgc2VsZWN0KGFydGlzdCwgdHJhY2ssIHN0cmVhbSwgdmlld3MpICU+JSAKICBtdXRhdGUoZGlmZmVyZW5jZSA9IGFicyhzdHJlYW0tdmlld3MpKSAlPiUgCiAgZ3JvdXBfYnkoYXJ0aXN0KSAlPiUgCiAgc3VtbWFyaXNlKAogICAgdG90YWxfdmlld3MgPSBzdW0odmlld3MpLzEwMDAwMDAsCiAgICB0b3RhbF9zdHJlYW1zID0gc3VtKHN0cmVhbSkvMTAwMDAwMCwKICApCiMjY3JlYXRlIGEgc2NhdHRlcnBsb3Qgd2l0aCBsaW5lIG9mIGJlc3QgZml0CnN0cmVhbXNfdmlld3MgJT4lIAogIGdncGxvdChhZXMoeD10b3RhbF9zdHJlYW1zLCB5PXRvdGFsX3ZpZXdzKSkrCiAgZ2VvbV9wb2ludChzaXplPTIpKwogIHRoZW1lX21pbmltYWwoKSsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iKSsKICBsYWJzKAogICAgdGl0bGUgPSAiQ29ycmVsYXRpb24gYmV0d2VlbiBhbiBhcnRpc3QncyBTcG90aWZ5IFN0cmVhbXMgYW5kIFlvdXR1YmUgVmlld3MiLAogICAgeCA9ICJOdW1iZXIgb2YgU3RyZWFtcyBvbiBTcG90aWZ5IiwKICAgIHkgPSAiTnVtYmVyIG9mIFZpZXdzIG9uIFlvdXR1YmUiCiAgKQoKIyNOb3RlcyBmb3IgbW9yZSBpbnZlc3RpZ2F0aW9uCiAgIyN3aGF0IHdhcyBoYXBwZW5pbmcgd2hlbiB0aGF0IHdhc24ndCB0aGUgY2FzZSwgd2hvIHdhcyBzdWNjZXNzZnVsIG9uIHNwb3RpZnkgYW5kIHRoZW4gbm90IHlvdXR1YmUKYGBgCgoqKlF1ZXN0aW9uIDM6IEhvdyBtYW55IHZpZGVvcyB3aXRoIGEgaGlnaCBudW1iZXIgb2Ygc3RyZWFtcyBhcmUgY29taW5nIGZyb20gbGljZW5zZWQgY29udGVudD8qKgoKKipBbmFseXNpcyoqOiBNb3N0IHZpZGVvcyBvbiBZb3VUdWJlIHdpdGggdmlld3Mgb3ZlciA1MDAgbWlsbGlvbiBhcmUgY29taW5nIGZyb20gbGljZW5zZWQgY29udGVudC4gSG93ZXZlciwgd2UgZm91bmQgdGhhdCB0aGVyZSBhcmUgc29tZSBvdXRsaWVycy4gQWJvdXQgNTQgdmlkZW9zIHdlcmUgdW5saWNlbnNlZCBhbmQgMTUgY2hhbm5lbHMgcG9zdGVkIHVubGljZW5zZWQgdmlkZW9zIHRoYXQgd2VyZSBhbHNvIGNsYXNzaWZpZWQgYXMgdGhlIG9mZmljaWFsIHZpZGVvIGZvciB0aGUgdHJhY2suIFNvbWUgY2hhbm5lbHMgc2F5IHRoZXkgYXJlIG9mZmljaWFsLCBsaWtlIE1ham9yIExhemVyIE9mZmljaWFsLCBhbmQgdGhlbiB0aGV5IG9ubHkgaGF2ZSB1bmxpY2Vuc2VkIGNvbnRlbnQgb24gdGhlIHBsYXRmb3JtLiBUaGVyZSBpcyBubyBvbmUgY29uc2lzdGVudCB0aGVtZSBvciB0cmVuZCBiZXR3ZWVuIHRoZSBjaGFubmVscyB0aGF0IGhhdmUgcG9zdGVkIHVubGljZW5zZWQgY29udGVudCwgdGhvdWdoIGl0IHNlZW1zIGxpa2Ugc29tZSBvZiB0aGVtIGFyZSBmcm9tIGNvdW50cmllcyBvdXRzaWRlIG9mIHRoZSBVLlMuIG9yIHJhcHBlcnMgYW5kIERKcy4gUmVkYm94IGFsc28gcG9zdGVkIHVubGljZW5zZWQgdmlkZW9zLCB3aGljaCBpcyBpbnRlcmVzdGluZyBjb21pbmcgZnJvbSBhIGNvbXBhbnkgZXZlbiB0aG91Z2ggaXQgaXMgbm90IGFzIHBvcHVsYXIgYW55bW9yZS4gSXQgc2VlbXMgbGlrZSBzb21lIGNoYW5uZWxzIGFyZSBkZWZpbml0ZWx5IHJlcHVycG9zaW5nIGNvbnRlbnQgZnJvbSBhbiB1bnZlcmlmaWVkIHVzZXIsIGxpa2UgV09STERTVEFSSElQSE9QIG9yIHBlcmhhcHMgb3RoZXIgY29udGVudCBpcyByZW1peGVzIG9yIGxpdmUgcGVyZm9ybWFuY2VzIGluIHRoZSBjYXNlIG9mIERKcy4gSW4gZG9pbmcgcGl2b3Qgd2lkZXIsIHdlIGNhbiBmaWx0ZXIgZm9yIGxpY2Vuc2VkIGFuZCB1bmxpY2Vuc2VkIGNvbnRlbnQgYXMgd2VsbCBhcyBvZmZpY2lhbCB2aWRlb3MgYW5kIHZpZXcgdGhlIHRvdGFsIG51bWJlciBvZiB2aWV3cyBmb3IgZWFjaCBzb3J0ZWQgYnkgY2hhbm5lbC4KCmBgYHtyfQojI2ZpbHRlciB0byBjcmVhdGUgYSBuZXcgZGF0YWZyYW1lIHdpdGggWW91VHViZSB2aWRlb3MgdGhhdCBoYXZlIG92ZXIgNTAwIG1pbGxpb24gdmlld3MKeW91dHViZV9oaWdoX3ZpZXdzIDwtIHNwb3RpZnlfeW91dHViZSAlPiUKICBmaWx0ZXIodmlld3MgPiA1MDAwMDAwMDApCiMjdHJ5aW5nIHRvIGNvdW50IGhvdyBtYW55IGxpY2Vuc2VkIHZpZGVvcyBhcnRpc3RzIGhhdmUKeW91dHViZV9oaWdoX3ZpZXdzICU+JQogIGdyb3VwX2J5KGFydGlzdCkgJT4lCiAgc3VtbWFyaXNlICgKICAgIGNvdW50X2xpY2Vuc2VkID0gbigpCiAgKSAlPiUKICBhcnJhbmdlKGRlc2MoY291bnRfbGljZW5zZWQpKQojI2ZpbHRlciBmb3IgdmlkZW9zIHRoYXQgYXJlIG5vdCBsaWNlbnNlZAp5b3V0dWJlX2hpZ2hfdmlld3MgJT4lCiAgZmlsdGVyKGxpY2Vuc2VkID09IEZBTFNFKSAKIyNmaW5kaW5nIHRoZSBhbW91bnQgb2Ygdmlld3MgZm9yIHZpZGVvcyB0aGF0IGFyZSBsaWNlbnNlZCBhbmQgdW5saWNlbnNlZCBhbmQgZ3JvdXBpbmcgaXQgYnkgY2hhbm5lbAp5b3V0dWJlX2hpZ2hfdmlld3MgJT4lCiAgZ3JvdXBfYnkoY2hhbm5lbCwgbGljZW5zZWQpICU+JQogIHN1bW1hcml6ZSh0b3RhbF92aWV3cyA9IHN1bSh2aWV3cykpICU+JSAKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gbGljZW5zZWQsIHZhbHVlc19mcm9tID0gdG90YWxfdmlld3MpCiMjZmluZGluZyB0aGUgbnVtYmVyIG9mIHZpZXdzIGZvciB2aWRlb3MgdGhhdCBhcmUgdW5saWNlbnNlZCBidXQgaXQgaXMgdGhlIG9mZmljaWFsIHZpZGVvIGFuZCBncm91cGluZyBpdCBieSBjaGFubmVsIAp5b3V0dWJlX2hpZ2hfdmlld3MgJT4lCiAgZ3JvdXBfYnkoY2hhbm5lbCwgb2ZmaWNpYWxfdmlkZW8pICU+JQogIHN1bW1hcml6ZSh0b3RhbF92aWV3cyA9IHN1bSh2aWV3cykpICU+JSAKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gb2ZmaWNpYWxfdmlkZW8sIHZhbHVlc19mcm9tID0gdG90YWxfdmlld3MpICU+JSAKICBmaWx0ZXIoYEZBTFNFYCA+IDApCmBgYAoKKipRdWVzdGlvbiA0OiBIb3cgZG8gY29sbGFib3JhdGlvbnMgb3IgZmVhdHVyZXMgb24gYSBzb25nIGFmZmVjdCBpdHMgcG9wdWxhcml0eSBvbiBTcG90aWZ5IGFuZCBZb3VUdWJlPyBXaGF0IGFyZSB0aGUgbW9zdCBwb3B1bGFyIGNvbGxhYm9yYXRpb25zPyoqCgoqKkFuYWx5c2lzKio6IFNvbWUgYXJ0aXN0cyBkZWZpbml0ZWx5IHNlZW0gdG8gYmUgbW9yZSBzdWNjZXNzZnVsIHdpdGggdGhlaXIgc29uZ3MgdGhhdCBoYXZlIGNvbGxhYm9yYXRvcnMgb24gdGhlIHRyYWNrIGNvbXBhcmVkIHRvIHNvbmdzIHdoZXJlIHRoZXkgYXJlIHRoZSBzb2xlIGFydGlzdC4gV2Ugd2VyZSB0cnlpbmcgdG8gZG8gYSBzaW1pbGFyIGFuYWx5c2lzIHRvIHRoZSBxdWVzdGlvbiBhYm92ZSB1c2luZyBwaXZvdF93aWRlciB0byBjb21wYXJlIHRoZSBudW1iZXIgb2Ygc3RyZWFtcyBmb3Igc29uZ3Mgd2l0aCBhIGNvbGxhYm9yYXRvciBhbmQgd2l0aG91dCBzbyB3ZSBjb3VsZCBzZWUgd2hpY2ggYXJ0aXN0cyB3b3VsZCBiZSBiZXN0IHRvIGNvbGxhYm9yYXRlIHdpdGggaWYgeW91IHdhbnQgeW91ciBzb25nIHRvIHJlYWNoIHRoZSBtb3N0IHBlb3BsZS4gV2UgcmFuIGludG8gYW4gZXJyb3IgdHJ5aW5nIHRvIHVzZSBwaXZvdCB3aWRlciBpbiB0aGUgZW5kLCBzbyB3ZSB3aWxsIGRlZmluaXRlbHkgbmVlZCB0byBicmFpbnN0b3JtIG1vcmUgc29sdXRpb25zIHRoYXQgd2lsbCBtb3ZlIHVzIHBhc3QgdGhpcyBkZWFkIGVuZCBiZWZvcmUgd2UgY29tcGxldGUgbW9yZSBhbmFseXNpcy4gRWl0aGVyIHdheSwgUG9zdCBNYWxvbmUgaXMgdGhlIG9ubHkgYXJ0aXN0IHdobyBoYWQgc3RyZWFtcyBpbiB0aGUgdG9wIDEwIGZvciBib3RoIGEgc2luZ2xlIHNvbmcgYW5kIGEgY29sbGFib3JhdGlvbi4gTWFja2VsbW9yZSBhbmQgUnlhbiBMZXdpcyB3ZXJlIGFsc28gaW4gdGhlIHRvcCAxMCBoaWdoZXN0IG51bWJlciBvZiBzdHJlYW1zIGZvciB0aGVpciBjb2xsYWJvcmF0aXZlIHNvbmdzLCBidXQgZmFsbCBiZWhpbmQgZm9yIHNpbmdsZSBzb25ncy4gQWxzbywgd2Ugbm90aWNlZCBhIGNvbXBsaWNhdGlvbiB3aXRoIHRoZSBkYXRhIHdoZW4gZG9pbmcgYW4gYW5hbHlzaXMgbGlrZSB0aGlzIHRvIGFuc3dlciB0aGUgcXVlc3Rpb24gYmVjYXVzZSBzb25ncyB3aWxsIGFwcGVhciB0d2ljZSB1bmRlciB0aGUgZGlmZmVyZW50IGFydGlzdHMnIG5hbWVzIGV2ZW4gdGhvdWdoIGl0IGlzIHRoZSBzYW1lIHNvbmcuIFRoaXMgY2FuIGJlIHNlZW4gZXNwZWNpYWxseSB3aXRoIE1hY2tlbG1vcmUgYW5kIFJ5YW4gTGV3aXMgc2luY2UgdGhlIHNvbmcgYXBwZWFycyB1bmRlciBNYWNrZWxtb3JlLCBSeWFuIExld2lzIGFuZCBNYWNrZWxtb3JlIGFuZCBSeWFuIExld2lzLiBJbmR1c3RyeSBCYWJ5IGFuZCBMZXZpdGF0aW5nIGFsc28gYXBwZWFyIHR3aWNlLCBvbmNlIHVuZGVyIGVhY2ggYXJ0aXN0J3MgbmFtZSwgdGhyb3dpbmcgb2ZmIHRoZSB0b3AgMTAgbW9zdCBzdHJlYW1lZCBjb2xsYWJvcmF0aXZlIHNvbmdzLgoKYGBge3J9CiMjZmlsdGVyaW5nIHRvIGNyZWF0ZSBhIG5ldyBkYXRhZnJhbWUgdGhhdCBvbmx5IGluY2x1ZGVzIHNvbmdzIHRoYXQgaGF2ZSBvbmUgb3IgbW9yZSBhcnRpc3RzIGZlYXR1cmVkIG9uIHRoZSB0cmFjayBpbmNsdWRpbmcgdGhlIG1haW4gYXJ0aXN0CnNvbmdfZmVhdHVyZXMgPC0gc3BvdGlmeV95b3V0dWJlICU+JQogIGZpbHRlcihzdHJfZGV0ZWN0KHRyYWNrLCAnZmVhdC4nKSkKCiMjc29ydGluZyB0aHJvdWdoIHRoZSBkYXRhZnJhbWUgdG8gZmluZCB0aGUgYXJ0aXN0IHdobyBoYXMgdGhlIGhpZ2hlc3QgbnVtYmVyIG9mIHN0cmVhbXMgd2l0aCBhIGNvbGxhYm9yYXRvciBvbiB0aGVpciB0cmFjawpzb25nX2ZlYXR1cmVzICU+JQogIGdyb3VwX2J5KGFydGlzdCwgc3RyZWFtKSAlPiUKICBhcnJhbmdlKGRlc2Moc3RyZWFtKSkKCnNwb3RpZnlfeW91dHViZSAlPiUKICBncm91cF9ieShhcnRpc3QpICU+JQogIGZpbHRlcihzdHJfZGV0ZWN0KHRyYWNrLCAnZmVhdC4nKSkgJT4lCiAgYXJyYW5nZShkZXNjKHN0cmVhbSkpCiMjZmlsdGVyaW5nIGZvciB0cmFja3Mgd2hlcmUgdGhlcmUgYXJlIG5vIGNvbGxhYm9yYXRvcnMgYW5kIGdyb3VwaW5nIGl0IGJ5IGFydGlzdCBpbiB0aGUgb3JkZXIgb2YgaGlnaGVzdCBzdHJlYW1zIHRvIGxvd2VzdApzcG90aWZ5X3lvdXR1YmUgJT4lCiAgZ3JvdXBfYnkoYXJ0aXN0KSAlPiUKICBmaWx0ZXIoIXN0cl9kZXRlY3QodHJhY2ssJ2ZlYXQuJykpICU+JQogIGFycmFuZ2UoZGVzYyhzdHJlYW0pKQojI2F0dGVtcHRpbmcgdG8gdXNlIHBpdm90X3dpZGVyIHRvIGNvbXBhcmUgdGhlIGFtb3VudCBvZiBzdHJlYW1zIGZvciB0cmFja3Mgd2l0aCBjb2xsYWJvcmF0b3JzIGFuZCB0cmFja3Mgd2l0aG91dC4Kc3BvdGlmeV95b3V0dWJlICU+JQogIGdyb3VwX2J5KGFydGlzdCkgJT4lCiAgc3VtbWFyaXplKHRvdGFsX3N0cmVhbSA9IHN1bShzdHJlYW0pKSAlPiUgCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IHRyYWNrLCB2YWx1ZXNfZnJvbSA9IHRvdGFsX3N0cmVhbSkgJT4lCiAgZmlsdGVyKHN0cl9kZXRlY3QodHJhY2ssJ2ZlYXQuJykpCiAgCiMjTm90ZXMgZm9yIG1vcmUgaW52ZXN0aWdhdGlvbjoKICAjI0hvdyB0byBjb3VudCBob3cgbWFueSBmZWF0dXJlcyBhbiBhcnRpc3QgaGFzLCBpc3N1ZSBvZiByZXBlYXRzIHdoZXJlIHRoZSBzYW1lIHNvbmcgaXMgbGlzdGVkIHVuZGVyIG1vcmUgdGhhbiBvbmUgYXJ0aXN0IChNYWNrZWxtb3JlIGFuZCBSeWFuIExld2lzKQogICMjVHJ5IHRvIHNlZSB3aG8gY29sbGFib3JhdGVycyBhcmUgZm9yIGF0IGxlYXN0IG9uZSBhcnRpc3Qgd2hvIGlzIG1vcmUgc3VjY2Vzc2Z1bCB3aXRoIHNvbWVvbmUgZWxzZSBvbiB0aGVpciB3b3JrCiAgIyNGaW5kIHRoZSBhdmVyYWdlIHZpZXdzIGZvciBhcnRpc3RzIGJ5IHRoZW1zZWx2ZXMgYW5kIHRoZW4gYXJ0aXN0IHZpZXdzIHdpdGggdGhlaXIgY29sbGFib3JhdGl2ZSB3b3JrLCBmaWx0ZXIgZm9yIGZlYXR1cmVkIGFuZCB0aGVuIGZpbHRlciBmb3Igbm90IGZlYXR1cmVkCmBgYAoKIyNJIHBsYXllZCBhcm91bmQgd2l0aCB1bmlxdWUgd29yZHMgZm9yIHRoZSBkZXNjcmlwdGlvbnMgb2YgWW91VHViZSB2aWRlb3MgYnV0IHRoZW4gZGVjaWRlZCB0byBkaXRjaCBteSBlZmZvcnRzIGJlY2F1c2UgdGhleSB3ZXJlbid0IHJlYWxseSB0aGF0IHJlbGV2YW50IHRvIGFueSBtYWpvciBuZXdzd29ydGh5IGZpbmRpbmdzLgoKYGBge3J9CnNwb3RpZnlfeW91dHViZV90ZXh0IDwtIHNwb3RpZnlfeW91dHViZSAlPiUKICBtdXRhdGUodGV4dCA9IGRlc2NyaXB0aW9uKQoKdW5pcXVlX3dvcmRzIDwtIHNwb3RpZnlfeW91dHViZV90ZXh0ICU+JSBzZWxlY3QodGV4dCkgJT4lCiAgdW5uZXN0X3Rva2Vucyh3b3JkLCB0ZXh0KQoKdW5pcXVlX3dvcmRzICU+JQogIGNvdW50KHdvcmQsIHNvcnQgPSBUUlVFKSAlPiUKICB0b3BfbigyNSkgJT4lCiAgbXV0YXRlKHdvcmQgPSByZW9yZGVyKHdvcmQsIG4pKSAKCmBgYAoqKlF1ZXN0aW9uIDU6IERvIHNpbmdsZXMgb3Igc29uZ3MgZnJvbSBmdWxsIGFsYnVtcyBnZXQgbW9yZSBzdHJlYW1zPyBXaGF0IGFib3V0IHZpZXdzIG9uIFlvdVR1YmU/IFdoaWNoIGFydGlzdHMgaGF2ZSBtb3JlIHN1Y2Nlc3Mgd2l0aCBzaW5nbGVzIGNvbXBhcmVkIHRvIGZ1bGwgYWxidW1zIGFuZCB2aWNlIHZlcnNhPyoqCgoqKkFuYWx5c2lzKio6IE1vcmUgd2VsbCBrbm93biBBbWVyaWNhbiBhcnRpc3RzIHdlcmUgaW4gdGhlIHRvcCAxMCBoaWdoZXN0IHZpZXdzIGZvciBZb3VUdWJlIHZpZGVvcyBjb21pbmcgZnJvbSBzb25ncyB0aGF0IHdlcmUgcGFydCBvZiBhIGZ1bGwgYWxidW0uIEEgbG90IG9mIHRoZSBzaW5nbGVzIHdlcmUgYWxzbyBzb25ncyB0aGF0IGhhZCBjb2xsYWJvcmF0aW9ucyBiZXR3ZWVuIGFydGlzdHMuIE5vbmUgb2YgdGhlIGFydGlzdHMgd2hvIGhhZCB0aGUgdG9wIG51bWJlciBvZiBzdHJlYW1zIGZvciBzaW5nbGVzIGFsc28gaGFkIHRoZSB0b3AgbnVtYmVyIG9mIHN0cmVhbXMgZm9yIHNvbmdzIG9uIGEgZnVsbCBhbGJ1bS4gUGVyaGFwcyBjb2xsYWJvcmF0aXZlIHNvbmdzIGFsc28gcGVyZm9ybSBiZXR0ZXIgd2hlbiB0aGV5IGFyZSBhIHNpbmdsZSByYXRoZXIgdGhhbiBmZWF0dXJlZCBpbiBhbiBhbGJ1bS4gVGhlIGhpZ2hlc3QgbnVtYmVyIG9mIHN0cmVhbXMgZm9yIGEgc29uZyB0aGF0IGNhbWUgZnJvbSBhbiBhbGJ1bSB3YXMgVGhlIFdlZWtuZCdzICJCbGluZGluZyBMaWdodHMiIHdoaWNoIGhhZCBhYm91dCBhIGJpbGxpb24gbW9yZSBzdHJlYW1zIHRoYW4gSGFsc2V5J3MgIkNsb3NlciIgd2hpY2ggaXMgdGhlIHRvcCBzaW5nbGUgd2l0aCB0aGUgbW9zdCBhbW91bnQgb2Ygc3RyZWFtcy4gVGhlIHRvcCB2aWRlb3Mgd2l0aCB0aGUgaGlnaGVzdCB2aWV3cyBmb3Igc2luZ2xlcyBhbmQgcmVndWxhciBhbGJ1bSB0cmFja3Mgd2VyZSBhbHNvIG11Y2ggZGlmZmVyZW50IHRoYW4gdGhlIHJlc3VsdHMgZnJvbSB0aGUgU3BvdGlmeSBzdHJlYW1zIGluIHRoZXNlIGNhdGVnb3JpZXMuIFdoYXQgdGhpcyBjb3VsZCB0ZWxsIHVzIGlzIHRoYXQgbWF5YmUganN1dCBiZWNhdXNlIGEgc29uZyBpcyBwb3B1bGFyIGRvZXMgbm90IG1lYW4gdGhlIHZpZGVvIHRvIGdvIHdpdGggaXQgd2lsbCBiZSBhcyB3ZWxsLiBUaGVyZSBhcmUgZGVlcGVyIHZpc3VhbCBhc3BlY3RzIGFuZCBzb2NpYWwgdHJlbmRzIHRoYXQgbWF5IGNvbnRyaWJ1dGUgbW9yZSB0byB0aGUgbnVtYmVyIG9mIHZpZXdzIG9uIFlvdVR1YmUuIAoKYGBge3J9CiMjZmlsdGVyaW5nIGZvciBzaW5nbGVzIGFuZCBhcnJhbmdpbmcgdGhlbSBmcm9tIGhpZ2hlc3QgbnVtYmVyIG9mIHN0cmVhbXMgdG8gbG93ZXN0CnNwb3RpZnlfeW91dHViZSAlPiUKICBmaWx0ZXIoYWxidW1fdHlwZSA9PSAic2luZ2xlIikgJT4lCiAgYXJyYW5nZShkZXNjKHN0cmVhbSkpCiMjZmlsdGVyaW5nIGZvciB0cmFja3MgZnJvbSBmdWxsIGFsYnVtcyBhbmQgYXJyYW5naW5nIHRoZW0gZnJvbSBoaWdoZXN0IG51bWJlciBvZiBzdHJlYW1zIHRvIGxvd2VzdCAKc3BvdGlmeV95b3V0dWJlICU+JQogIGZpbHRlcihhbGJ1bV90eXBlID09ICJhbGJ1bSIpICU+JQogIGFycmFuZ2UoZGVzYyhzdHJlYW0pKSAKIyNjb3VudGluZyB0aGUgbnVtYmVyIG9mIHNpbmdsZXMgYW5kIGZ1bGwgYWxidW0gdHJhY2tzIGVhY2ggYXJ0aXN0IGhhcwpzcG90aWZ5X3lvdXR1YmUgJT4lCiAgZmlsdGVyKGFsYnVtX3R5cGUgPT0gInNpbmdsZSIpICU+JQogIGdyb3VwX2J5KGFydGlzdCkgJT4lCiAgc3VtbWFyaXNlICgKICAgIGNvdW50X3RyYWNrID0gbigpCiAgKSAlPiUKICBhcnJhbmdlKGRlc2MoY291bnRfdHJhY2spKQoKc3BvdGlmeV95b3V0dWJlICU+JQogIGZpbHRlcihhbGJ1bV90eXBlID09ICJhbGJ1bSIpICU+JQogIGdyb3VwX2J5KGFydGlzdCkgJT4lCiAgc3VtbWFyaXNlICgKICAgIGNvdW50X3RyYWNrID0gbigpCiAgKSAlPiUKICBhcnJhbmdlKGRlc2MoY291bnRfdHJhY2spKQoKIyNjb3VudGluZyB0aGUgbnVtYmVyIG9mIHNpbmdsZSB2aWRlb3MgYW5kIGFsYnVtIHRyYWNrIHZpZGVvcyBhbiBhcnRpc3QgaGFzCnlvdXR1YmVfaGlnaF92aWV3cyAlPiUKZmlsdGVyKGFsYnVtX3R5cGUgPT0gInNpbmdsZSIpICU+JQogIGdyb3VwX2J5KGFydGlzdCkgJT4lCiAgc3VtbWFyaXNlICgKICAgIGNvdW50X3RpdGxlID0gbigpCiAgKSAlPiUKICBhcnJhbmdlKGRlc2MoY291bnRfdGl0bGUpKQoKeW91dHViZV9oaWdoX3ZpZXdzICU+JQpmaWx0ZXIoYWxidW1fdHlwZSA9PSAiYWxidW0iKSAlPiUKICBncm91cF9ieShhcnRpc3QpICU+JQogIHN1bW1hcmlzZSAoCiAgICBjb3VudF90aXRsZSA9IG4oKQogICkgJT4lCiAgYXJyYW5nZShkZXNjKGNvdW50X3RpdGxlKSkKIyNhcnJhbmdlIHRvIHNlZSB3aGljaCB2aWRlb3MgaGF2ZSB0aGUgaGlnaGVzdCBudW1iZXIgb2Ygdmlld3MgZm9yIHNpbmdsZXMgYW5kIHRyYWNrcyBmcm9tIGFuIGFsYnVtCnlvdXR1YmVfaGlnaF92aWV3cyAlPiUKZmlsdGVyKGFsYnVtX3R5cGUgPT0gInNpbmdsZSIpICU+JQogIGdyb3VwX2J5KGFydGlzdCkgJT4lCiAgYXJyYW5nZShkZXNjKHZpZXdzKSkKCnlvdXR1YmVfaGlnaF92aWV3cyAlPiUKZmlsdGVyKGFsYnVtX3R5cGUgPT0gImFsYnVtIikgJT4lCiAgZ3JvdXBfYnkoYXJ0aXN0KSAlPiUKICBhcnJhbmdlKGRlc2Modmlld3MpKQoKYGBgCioqT3VyIG1vc3QgbmV3c3dvcnRoeSBmaW5kaW5nKioKU28gZmFyLCB3ZSB0aGluayBvdXIgbW9zdCBuZXdzd29ydGh5IHBpZWNlIG9mIGFuYWx5c2lzIGNvbWVzIGZyb20gZWl0aGVyIHRoZSBsaWNlbnNlZCBhbmQgdW5saWNlbnNlZCBjb250ZW50IG9uIFlvdVR1YmUgb3IgdGhlIGFuYWx5c2lzIG9mIGFydGlzdCBjb2xsYWJvcmF0aW9ucy4gV2UgdGhpbmsgdGhhdCBvbmNlIHdlIGFyZSBhYmxlIHRvIGNvbXBsZXRlIG1vcmUgYW5hbHlzaXMgb24gYXJ0aXN0IGNvbGxhYm9yYXRpb25zLCBpdCB3b3VsZCBtYWtlIGZvciBhIHJlYWxseSBpbnRlcmVzdGluZyBhcnRpY2xlIGFib3V0IHdobyB0byBmZWF0dXJlIG9uIHlvdXIgdHJhY2sgaWYgeW91IHdhbnQgeW91ciBzb25nIHRvIGFtYXNzIGEgbG90IG9mIHN0cmVhbXMgb24gU3BvdGlmeS4gRnJvbSB3aGF0IHdlIGhhdmUgc2VlbiwgdGhlcmUgaGF2ZSBub3QgYmVlbiBhbnkgYXJ0aWNsZXMgd2l0aCBhIGNlbnRyYWwgZm9jdXMgYWxvbmcgdGhlIGxpbmVzIG9mICJIZXJlJ3Mgd2hvIHRvIG1ha2Ugc29uZ3Mgd2l0aCBpZiB5b3Ugd2FudCB0aGVtIHRvIHRha2Ugb2ZmLCIgd2hpY2ggd2UgdGhpbmsgY291bGQgYmUgYW4gaW1wYWN0ZnVsIGZpbmRpbmcgaW4gYW5kIGFyb3VuZCB0aGUgbXVzaWMgY29tbXVuaXR5LiBBbHNvLCB3aXRoIHRoZSBjb25zdW1wdGlvbiBvZiB2aWRlbyBvbiB0aGUgcmlzZSBiZXR3ZWVuIFRpa1RvayBhbmQgWW91VHViZSwgd2UgdGhpbmsgaXQgaXMgbmV3c3dvcnRoeSB0byBxdWVzdGlvbiB3aHkgY2VydGFpbiBjaGFubmVscyBoYXZlIHVubGljZW5zZWQgY29udGVudCBvciBob3cgdGhlaXIgdmlkZW9zIGNhbiBiZSBvZmZpY2lhbCBidXQgdW5saWNlbnNlZC4gQXMgd2UgbGVhcm4gbW9yZSBhYm91dCBob3cgdG8gbmF2aWdhdGUgc29jaWFsIG1lZGlhIHNwYWNlcyBpbiB0ZXJtcyBvZiByZWd1bGF0aW5nIGNvbnRlbnQgYW5kIGNvcHlyaWdodCwgcGVyaGFwcyB0aGVzZSBmaW5kaW5ncyBjYW4gcHJvdmlkZSBtb3JlIGluc2lnaHQgZm9yIHRob3NlIHdobyBtYWtlIHNvY2lhbCBtZWRpYSBydWxlcyBvciB3aG8gd29yayBmb3IgdGhlIHNvY2lhbCBtZWRpYSBjb21wYW5pZXMgYW5kIGFyZSB0cnlpbmcgdG8gbGltaXQgdW5saWNlbnNlZCBjb250ZW50LiAK